//
// Created by liuqiang on 25-7-8.
//

#ifndef ATOMICDOUBLEBUFFER_H
#define ATOMICDOUBLEBUFFER_H

template <typename T>
class atomic_double_buffer
{
public:
    void write(const T &data)
    {
        const int next = (index.load(std::memory_order_relaxed) + 1) % 2;
        buffer[next] = data;
        std::atomic_thread_fence(std::memory_order_release);
        index.store(next, std::memory_order_release);
        ready.store(true, std::memory_order_relaxed);
    }

    bool read(T &out) const
    {
        if (!ready.load(std::memory_order_acquire))
        {
            return false;
        }
        const int idx = index.load(std::memory_order_acquire);
        std::atomic_thread_fence(std::memory_order_acquire);
        out = buffer[idx];
        return true;
    }

private:
    T buffer[2];
    std::atomic<int> index{0};
    std::atomic<bool> ready{false};
};

#endif // ATOMICDOUBLEBUFFER_H
